using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Drawing.Drawing2D;
using System.Runtime.Serialization;
using System.Collections.Generic;
using OpenComposite.Workflow.Design;
using System.Collections.Specialized;
using System.Drawing.Design;
using OpenComposite.Workflow.Interfaces;
using OpenComposite.Workflow.Properties;
using System.Reflection;

namespace OpenComposite.Workflow
{
	[Designer(typeof(LogicalAsyncEndActivityDesigner))]
	[ToolboxItem(typeof(LogicalAsyncEndActivityToolboxItem))]
	[ToolboxBitmap(typeof(resfinder), "OpenComposite.Workflow.Resources.logact_async_end.png")]
	[ActivityValidator(typeof(LogicalAsyncEndActivityValidator))]
	public partial class LogicalAsyncEndActivity
		: LogicalCapabilityActivity, IPropertyValueProvider
	{
		public LogicalAsyncEndActivity()
		{
			InitializeComponent();
		}

		#region StartActivityName
		[Category("Logical Async End")]
		[Browsable(true)]
		[RefreshProperties(RefreshProperties.All)]
		[MergableProperty(false)]
		[DefaultValue("")]
		[TypeConverter(typeof(PropertyValueProviderTypeConverter))]
		public string StartActivityName
		{
			get { return (string)GetValue(StartActivityNameProperty); }
			set { SetValue(StartActivityNameProperty, value); }
		}
		// Using a DependencyProperty as the backing store for StartActivity.
		public static readonly DependencyProperty StartActivityNameProperty =
			DependencyProperty.Register("StartActivityName", typeof(string),
										typeof(LogicalAsyncEndActivity), new PropertyMetadata(""));
		#endregion

		#region AsyncState
#if DEBUG
		[Browsable(true)]
#else
		[Browsable(false)]
#endif
		public LogicalAsyncState AsyncState
		{
			get { return (LogicalAsyncState)GetValue(AsyncStateProperty); }
			set { SetValue(AsyncStateProperty, value); }
		}

		// Using a DependencyProperty as the backing store for AsyncState.
		public static readonly DependencyProperty AsyncStateProperty =
			DependencyProperty.Register("AsyncState", typeof(LogicalAsyncState),
										typeof(LogicalAsyncEndActivity), new PropertyMetadata(null));

		//public object Output
		//{
		//    get { return AsyncState == null ? null : AsyncState.Output; }
		//    set { if ( AsyncState != null ) AsyncState.Output = value; }
		//}
		#endregion

		//#region ITrackingActivity Members

		//public void AddKPIData(string sKPIName, string sKPIValue, string sKPIUnit, string sKPIDataType)
		//{
		//    this.TrackData(sKPIName, new KPITrackingData(sKPIName, sKPIValue, sKPIUnit, sKPIDataType));
		//}

		//public void AddBusinessObjectData(string sBOName, object sBOValue)
		//{
		//    this.TrackData(sBOName, new BusinessObjectTrackingData(sBOName, sBOValue));
		//}

		//#endregion

		#region Execute Method
		protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
		{
			string wqname = this.StartActivityName + this.WorkflowInstanceId.ToString();
			WorkflowQueuingService qsvc = executionContext.GetService<WorkflowQueuingService>();
			if ( this.LogicalActivityId > 1 ) {
				return base.Execute(executionContext);
			} else if ( !qsvc.Exists(wqname) ) {
				base.Invoke(this.ContinueAt, EventArgs.Empty);
				return ActivityExecutionStatus.Executing;
			} else {
				ActivityExecutionStatus status = ActivityExecutionStatus.Executing;
				WorkflowQueue wq = qsvc.GetWorkflowQueue(wqname);
				if ( wq.Count > 0 ) {
					this.AsyncState = wq.Dequeue() as LogicalAsyncState;
					base.Invoke(this.ContinueAt, EventArgs.Empty);
					//status = ActivityExecutionStatus.Closed;
				} else {
					wq.QueueItemAvailable += new EventHandler<QueueEventArgs>(wq_QueueItemAvailable);
				}
				return status;
			}
		}
		#endregion

		#region Event Handlers
		private void ContinueAt(object sender, EventArgs e)
		{
			ActivityExecutionContext context = sender as ActivityExecutionContext;
			LogicalAsyncStartActivity startAct = this.GetActivityByName(this.StartActivityName, false) as LogicalAsyncStartActivity;
			object activitiesclass = startAct.ActivitiesClass;
			Type t = activitiesclass.GetType();
			if ( t != null ) {
				MethodInfo mi = t.GetMethod(string.Format("Receive{0}", startAct.LogicalActivityName));
				if ( mi != null ) {
					mi.Invoke(activitiesclass, new object[] { context, (ITrackingActivity)this });
				}
			}
			context.CloseActivity();
		}

		private void wq_QueueItemAvailable(object sender, QueueEventArgs e)
		{
			ActivityExecutionContext context = sender as ActivityExecutionContext;
			WorkflowQueuingService qsvc = context.GetService<WorkflowQueuingService>();
			WorkflowQueue wq = qsvc.GetWorkflowQueue(e.QueueName);
			wq.QueueItemAvailable -= new EventHandler<QueueEventArgs>(wq_QueueItemAvailable);
			this.AsyncState = wq.Dequeue() as LogicalAsyncState;
			base.Invoke(this.ContinueAt, EventArgs.Empty);
		}
		#endregion

		#region IPropertyValueProvider Members

		ICollection IPropertyValueProvider.GetPropertyValues(ITypeDescriptorContext context)
		{
			StringCollection values = new StringCollection();
			if ( context.PropertyDescriptor.Name == "StartActivityName" ) {
				foreach ( var item in WorkflowHelpers.GetPreceedingActivities(this) ) {
					if ( item is LogicalAsyncStartActivity ) values.Add(item.QualifiedName);
				}
			}
			return values;
		}

		#endregion

		//#region Text
		//public static DependencyProperty TextProperty = DependencyProperty.Register(
		//    "Text", typeof(string), typeof(LogicalAsyncEndActivity), new PropertyMetadata(""));
		//[Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
		//[DefaultValue("")]
		//[Browsable(true)]
		//public string Text
		//{
		//    get { return (string)base.GetValue(LogicalAsyncEndActivity.TextProperty); }
		//    set { base.SetValue(LogicalAsyncEndActivity.TextProperty, value); }
		//}

		//DependencyProperty ITextActivity.GetTextProperty()
		//{
		//    return TextProperty;
		//}
		//#endregion
	}

	#region Class: LogicalAsyncEndActivityToolboxItem : Base: ActivityToolboxItem
	[Serializable]
	internal class LogicalAsyncEndActivityToolboxItem : LogicalCapabilityActivityToolboxItem
	{
		public LogicalAsyncEndActivityToolboxItem(Type type)
			: base(type)
		{
			base.DisplayName = "Logical Async End";
		}

		protected override IComponent[] CreateComponentsCore(IDesignerHost host)
		{
			LogicalAsyncEndActivity act = new LogicalAsyncEndActivity();

			OnInitializeLogicalCapabilityActivity(act);

			return new IComponent[] { act };
		}
	}
	#endregion

	#region Class: LogicalAsyncEndActivityDesigner : Base: LogicalCapabilityActivityDesigner
	[ActivityDesignerTheme(typeof(LogicalAsyncEndActivityDesignerTheme))]
	internal class LogicalAsyncEndActivityDesigner : LogicalCapabilityActivityDesigner
	{
		public override Image Image
		{
			get { return Resources.logact_async_end; }
			protected set { base.Image = value; }
		}
	}
	#endregion

	#region Class: LogicalAsyncEndActivityDesignerTheme : Base: ActivityDesignerTheme
	internal class LogicalAsyncEndActivityDesignerTheme : ActivityDesignerTheme
	{
		public LogicalAsyncEndActivityDesignerTheme(WorkflowTheme theme)
			: base(theme)
		{
			base.Initialize();
			this.BorderStyle = DashStyle.Solid;
			this.BorderColor = Color.CornflowerBlue;
			this.BackColorStart = Color.CornflowerBlue;
			this.BackColorEnd = Color.White;
			this.BackgroundStyle = LinearGradientMode.Vertical;
			this.ForeColor = Color.Black;
		}
	}
	#endregion

	#region Class: LogicalAsyncEndActivityValidator : Base: ActivityValidator
	internal class LogicalAsyncEndActivityValidator : ActivityValidator
	{
		public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
		{
			ValidationErrorCollection errors = base.Validate(manager, obj);

			LogicalAsyncEndActivity act = obj as LogicalAsyncEndActivity;
			if ( act != null && act.Parent != null ) {
				if ( string.IsNullOrEmpty(act.StartActivityName) ) {
					// Start Activity is required
					errors.Add(
						new ValidationError("Please select the Start Activity.", 0, false, "StartActivity"));
				}
			}

			return errors;
		}
	}
	#endregion

}
